<?php
/**
 * @Author: liuhongbin
 * @Email: 514660094@qq.com
 * @Date: 2019-02-12 16:15:10
 * @Description:
 * @LastEditors: liuhongbin
 * @LastEditTime: xxx
 */

namespace hiduoke\services\wechat\traits;

use app\common\model\platform\PlatformAddon;
use app\common\model\platform\PlatformSetting;
use app\common\model\wechat\WechatUser;
use think\Exception;
use EasyWeChat\Factory;
use EasyWeChat\OfficialAccount\Application;
use app\common\model\platform\PlatformWechat;
use think\facade\Cache;
use think\facade\Cookie;
use think\facade\Log;
use think\facade\Session;

trait WechatAccountService
{
    /**
     * @var Application
     */
    protected $app;


    /**
     * 获取平台配置
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getConfig()
    {
        $callback_url = $this->getCallBackUrl();
        $Wechat = new PlatformWechat();
        $wechat = $Wechat->where(['plaid' => $this->plaid])->find();
        if (!$wechat) {
            throw new Exception(lang('The platform does not exist or has been deleted'), 10001);
        }
        $config = [
            'app_id'  => $wechat->appid,
            'secret'  => $wechat->secret,
            'oauth'   => [
                'scopes'   => ['snsapi_userinfo'],
                'callback' => $callback_url,
            ],
            'log'     => [
                'default'  => 'error', // 默认使用的 channel，生产环境可以改为下面的 prod
                'channels' => [
                    'error' => [
                        'driver' => 'single',
                        'path'   => '/tmp/easywechat/wechat_account_error.log',
                        'level'  => 'error',
                    ],
                ],
            ],
            'token'   => $wechat->token,
            'aes_key' => $wechat->encodingaeskey
        ];
        return $config;
    }

    /**
     * 公众号
     * @param array $config
     * @return Application
     */
    public function getApp($config = [])
    {
        if ($this->app) {
            return $this->app;
        } else {
            if ($config) {
                $this->config = $config;
            } else {
                $this->config = $this->getConfig();
            }
            $this->app = Factory::officialAccount($this->config);
            return $this->app;
        }
    }

    /**
     * 获取微信用户信息
     * @param bool $force_oauth 强制拉取用户信息
     * @param bool $userinfo 是否需要得到userinfo（false 静默授权）
     * @return false|mixed|string
     */
    public function getUser($force_oauth = true, $userinfo = true)
    {
        $wx_user = Cache::get($this->getKey('wx_user'));
        if (!empty($wx_user)) {
            $this->updateUser($wx_user['openid']);
            return $wx_user;
        } else {
            if (!$userinfo) {
                //记录当前地址
                Cache::set($this->getKey('target_url'), request()->url(), 600);
                Cache::set($this->getKey('scopes'), 'snsapi_base', 600);
                //跳转拉取授权
                to($this->getApp()->oauth->scopes(['snsapi_base'])->redirect());
                return '';
            } else {
                if ($force_oauth) {
                    //记录当前地址
                    Cache::set($this->getKey('target_url'), request()->url(), 600);
                    //跳转拉取授权
                    $url = $this->getApp()->oauth->redirect();
                    to($url);
                    return '';
                } else {
                    return false;
                }
            }

        }
    }

    public function clearUpdateWechat($uid)
    {
        Cache::delete('updateWechatUser-' . $uid);
    }

    /**
     * 更新用户信息
     * @param $uid string 用户id
     * @param false $isCache 忽略缓存
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function updateUser($uid, $isCache = false)
    {
        if (!$uid) return;
        $isUpdate = Cache::get('updateWechatUser-' . $uid);
        //判断是否能更新和是否强制更新
        if (!$isUpdate || $isCache) {
            $wechat_user = (new WechatUser())->find($uid);
            if ($wechat_user) {
                $topuid = input('topuid', Cookie::get('dk_topuid', 0));
                $addon = input('addon', Cookie::get('dk_addon', ''));
                $user_update_data = array();
                //判断是否为应用环境
                if ($addon) {
                    $user_update_data['last_addon'] = $addon;
                    if (!$wechat_user['first_addon']) {
                        $user_update_data['first_addon'] = $addon;
                    }
                }
                //判断是否可以更新上级ID
                if (!$wechat_user['topuid'] && $topuid && $topuid != $wechat_user['id']) {
                    $user_update_data['topuid'] = $topuid;
                }
                //判断是否可以更新团队ID
                if (!$wechat_user['teamuid'] && $topuid && $topuid != $wechat_user['id']) {
                    $teamuid = (new WechatUser())->where(['id' => $topuid])->value('teamuid');
                    if ($teamuid) {
                        $user_update_data['teamuid'] = $teamuid;
                    } else {
                        $user_update_data['teamuid'] = $topuid;
                    }
                }
                $wechat_user->save($user_update_data);
                Cache::set('updateWechatUser-' . $uid, 1);
            }
        }
    }

    /**
     * 获取微信用户信息（自定义授权页）
     * @return mixed|string
     */
    public function getUserOauth()
    {
        $wx_user = $this->getUser(false);
        if (!$wx_user) {
            $url = url('/h5/user/oauth', [
                'p'        => $this->plaid,
                'back_url' => request()->url()
                //                'back_id' => $this->getBackId(request()->url())
            ])->domain(true)->build();
            to($url);
            return '';
        } else {
            return $wx_user;
        }
    }

    public function getBackId($url)
    {
        $back_id = get_rand(0);
        if (!Cache::get($back_id)) {
            Cache::set($back_id, $url);
            return $back_id;
        } else {
            return $this->getBackId($url);
        }
    }

    /**
     * 获得用户的openid
     * @return false|mixed
     */
    public function getOpenid()
    {
        return $this->getUser(false)['openid'] ?? false;
    }

    /**
     * 获取jssdk配置项
     * @param false $debug
     * @param array $jsApiList
     * @return string
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function getJssdk($debug = false, $jsApiList = [])
    {
        try {
            if (!$jsApiList) {
                $jsApiList = [
                    'onMenuShareAppMessage',
                    'onMenuShareTimeline',
                    'onMenuShareQQ',
                    'onMenuShareQZone',
                    'updateAppMessageShareData', //分享接口
                    'updateTimelineShareData', //分享接口
                    'chooseWXPay', //支付
                    'scanQRCode', //扫码
                    'openLocation',//地图
                    'getLocation',//定位
                ];
            }
            $config = $this->getApp()->jssdk->buildConfig($jsApiList, $debug);
        } catch (\Exception $e) {
            echo $e->getMessage();
            throw new Exception($e->getMessage(), 10003);
        }
        $html = '
                <script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js" type="text/javascript" charset="utf-8"></script>
                <script type="text/javascript" charset="utf-8">
                 wx.config(' . $config . ');
                </script>
            ';
        return $html;
    }

    /**
     * 获取分享配置项
     * @param array $share
     * @param string $fun
     * @return string
     */
    public function getShare($share = [], $fun = '')
    {
        $share['title'] = isset($share['title']) ? $share['title'] : "默认分享标题";
        $share['desc'] = isset($share['desc']) ? $share['desc'] : "默认分享描述";
        $share['link'] = isset($share['link']) ? $share['link'] : get_url() . '&topuid=' . getWxUser()['id'];
        $share['img_url'] = isset($share['img_url']) ? $share['img_url'] : "";
        $html = '
        <script type="text/javascript" charset="utf-8">
            wx.ready(function () {   //需在用户可能点击分享按钮前就先调用
                wx.updateTimelineShareData({
                    title: "' . $share['title'] . '", // 分享标题
                    desc:  "' . $share['desc'] . '", // 分享描述
                    link:  "' . $share['link'] . '", // 分享链接，该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl:"' . $share['img_url'] . '", // 分享图标
                    success: function () {
                        // 设置成功
                        ' . $fun . '
                    }
                })
                wx.updateAppMessageShareData({
                    title: "' . $share['title'] . '", // 分享标题
                    desc:  "' . $share['desc'] . '", // 分享描述
                    link:  "' . $share['link'] . '", // 分享链接，该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl:"' . $share['img_url'] . '", // 分享图标
                    success: function () {
                        // 设置成功
                        ' . $fun . '
                    }
                })
            });
        </script>
        ';
        return $html;
    }


    /**
     * 获取缓存key
     * @param $string
     * @return string
     */
    protected function getKey($string)
    {
        return $string . Session::getid() . '_' . $this->plaid;
    }

    /**
     * 获取回调地址
     * @return string
     */
    public function getCallBackUrl()
    {
        $vars = ['p' => $this->plaid, 'sid' => Session::getid()];
        $topuid = input('topuid', 0);
        if ($topuid) $vars['topuid'] = $topuid;
        if ($this->addon_name) $vars['addon'] = $this->addon_name;
        $preference = (new PlatformSetting())->getValueByKey("preference", $this->plaid);
        $oauth_domain = $preference['oauth_domain'] ?? true;
        return url("/h5/Oauth/callBack", $vars)->domain($oauth_domain)->build();
    }
}
